
// 线程池

import {newPromise} from '../utils.js';

export default class ThreadPool {
  __v_skip = true; // 设置vue跳过代理

  _state = 0; // 0:销毁不可用状态，1:等待任务, 2:运行中

  _config = {
    coreSize: 4,
  };
  _workUrl = null; // 执行脚本url
  _threads = [];
  _taskQueue = [];
  


  /**
   * 初始化线程池
   * @param {Object} config 配置
   *  coreSize: 线城池大小，默认4个
   */
  constructor(config) {
    let self = this;
    config = Object.assign(self._config, config);
    if (config.coreSize > 24){
      throw new Error('线程池大小不能超过24');
    }
    let script = `(${threadCode.toString()})();`;
    self._workUrl = URL.createObjectURL(new Blob([script], { type: 'text/javascript' }));
    for (let i = 0; i < config.coreSize; i++) {
      if(i >= 24){
        throw new Error('线程池大小不能超过24');
      }
      let work = new Worker(self._workUrl);
      work.onmessage = function(e){
        self._workMessage(this, e);
      };
      work.state = 0; // 0:空闲，1:忙碌
      self._threads.push(work);
    }
    self._state = 1;
  }

  get state(){
    return this._state;
  }

  /**
   * 初始化，所有线程都会执行
   * @param {Function} task 初始方法
   * @param  {...any} args 方法需要的参数
   */
  init(fn, ...args) {
    if (!(fn instanceof Function)) {
      throw new Error('参数task必须是Function类型');
    }

    // 检查参数
    if (args) {
      for (let i = 0; i < args.length; i++) {
        if (args[i] instanceof Function) {
          throw new Error('参数' + i + '不能是Function类型');
        }
      }
    }

    let task = fn.toString();
    task = '(()=>' + task + ')()';
    this._threads.forEach(work=>{
      work.postMessage({task, args});
    });
  }

  /**
   * 提交一个任务到线城池
   * @param {Function} task 任务方法
   * @param  {...any} args 方法需要的参数
   */
  submit(task, ...args) {
    if (!(task instanceof Function)) {
      throw new Error('参数task必须是Function类型');
    }

    // 检查参数
    if (args) {
      for (let i = 0; i < args.length; i++) {
        if (args[i] instanceof Function) {
          throw new Error('参数' + i + '不能是Function类型');
        }
      }
    }

    // 封装dto
    let promise = newPromise();
    let dto = new Dto(task, args, promise);
    let self = this;
    // 提交到任务队列
    self._taskQueue.push(dto);
    self._run();

    return dto;
  }

  /**
   * 销毁线城池
   * @param {Boolean} immediately 是否立刻销毁
   */
  destroy(/* immediately */){
    this._threads.forEach(work=>{
      work.terminate();
    });

    // 销毁脚本对象
    URL.revokeObjectURL(this._workUrl);
    this._threads = [];
    this._taskQueue = [];
    this._state = 0;
  }

  _run() {
    // 获取一个可用的线程
    let self = this;
    if (self._state == 0){
      throw new Error('线程池不可用');
    }
    let work = self._threads.find(it => it.state == 0);
    if (work == null) {
      return;
    }

    // 获取一个任务
    let dto = self._taskQueue.shift();
    if (dto == null) {
      return;
    }
    work.state = 1;
    self._state = 2;
    work.dto = dto;
    let task = dto.task.toString();
    task = '(()=>' + task +')()';
    // task.replace(/function.*?\(/, 'function ' + Math.random().toString(36).substring(2, 10) +' (')
    work.postMessage({
      task: task,
      args: dto.args
    });
  }

  /**
   * 收到事件
   * @param {Worker} work 线程对象
   * @param {MessageEvent} e 通讯事件
   */
  _workMessage(work, e) {
    let result = e.data;
    let dto = work.dto;
    if (result.key == 0) { // 成功
      dto.resolve({
        in: dto.args,
        out: result.args
      });
      work.dto = null;
      work.state = 0;
    } else if(result.key == 1) { // 失败
      dto.reject({
        in: dto.args,
        out: result.args
      });
      work.dto = null;
      work.state = 0;
    } else {
      if (dto.onmessage instanceof Function){
        dto.onmessage(result, dto);
      }
      if (this.onmessage instanceof Function){
        this.onmessage(result, dto, work);
      }
      this.updateState();
    }
    // 执行后续任务
    this._run();
  }

  // 更新状态
  updateState(){
    let self = this;
    if(self._state == 0){
      return;
    }
    // 检查所有
    self._state = self._threads.some(it => it.state == 1) ? 2 : 1;
  }

}

/**
 * 线程执行主要方法
 */
function threadCode() {
  onmessage = function (e) {
    if (e.data == 'close'){
      close();
      return;
    }
    let dto = eval(e.data);
    let fn = eval(dto.task);
    fn.apply(null, dto.args);
  };
}


class Dto {
  task; // 执行的任务字符串
  args; // 参数
  promise;
  onmessage;
  constructor(task, args, promise) {
    this.task = task;
    this.args = args;
    this.promise = promise;
  }

  resolve(){
    return this.promise.resolve.apply(this.promise, arguments);
  }
  reject(){
    return this.promise.reject.apply(this.promise, arguments);
  }
  finally(){
    return this.promise.finally.apply(this.promise, arguments);
  }
}